package com.kobeliu.filter;

import com.google.gson.Gson;
import com.kobeliu.base.BaseInfoProperties;
import com.kobeliu.result.GraceJSONResult;
import com.kobeliu.result.ResponseStatusEnum;
import com.kobeliu.utils.JwtUtils;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
@Slf4j
public class SecurityFilterJwt extends BaseInfoProperties implements GlobalFilter, Ordered{

    public static final String HEADER_USER_TOKEN = "headerUserToken";

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private ExcludeUrlPathProperties excludeUrlPathProperties;

    //路径匹配工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //一键注册，登出，获取验证码不需要验证 token直接放行

        //1.获取需要放行的url集合
        List<String> urls = excludeUrlPathProperties.getUrls();

        //2.获取当前请求的路由
        String url = exchange.getRequest().getURI().getPath();

        //3.做校验并且排除
        if(urls !=null && !urls.isEmpty()){
            for(String excludeUrl:urls){
                if(antPathMatcher.matchStart(excludeUrl,url)){
                    //若匹配到直接放行
                    return chain.filter(exchange);
                }
            }
        }
        log.info("=====================");
        log.info("此处被拦截,当前路由：{}",url);
        log.info("=====================");

        //拦截时，查看请求中是否包含token 校验
        HttpHeaders headers = exchange.getRequest().getHeaders();
        String userToken = headers.getFirst(HEADER_USER_TOKEN);
       if(userToken==null) {
           userToken = headers.getFirst("Headerusertoken");
       }
       log.info("userToken:{}",userToken);
       log.info("====================================================");
        //判空header中的令牌
        if(StringUtils.isNotBlank(userToken)){
            String[] tokenArr = userToken.split(JwtUtils.AT);
            if(tokenArr.length>=2) {
                //获得jwt的prefix和令牌
                String prefix = tokenArr[0];
                String token = tokenArr[1];

                //判断并且处理用户信息
                if (prefix.equalsIgnoreCase(TOKEN_ADMIN_PREFIX)) {

                    //此时是user信息
                    return dealJwt(token,exchange,chain,ADMIN_USER_JSON);
                } else if (prefix.equalsIgnoreCase(TOKEN_SAAS_PREFIX)) {

                    //此时是user信息
                    return dealJwt(token,exchange,chain,SAAS_USER_JSON);
                }else {

                    //此时是user信息
                    return dealJwt(token,exchange,chain,APP_USER_JSON);
                }
            }
        }

        //默认放行
        return renderErrorFilter(exchange,ResponseStatusEnum.UN_LOGIN);
    }

    public Mono<Void> dealJwt(String jwt,ServerWebExchange exchange, GatewayFilterChain chain,String key){
        try{
            String userJson = jwtUtils.checkJwt(jwt);

            //若匹配到直接放行
            //在request 的header中添加了一个键值对
            return chain.filter(setNewHeaders(exchange,key,userJson));

        }catch (ExpiredJwtException e){
            e.printStackTrace();
            return renderErrorFilter(exchange,ResponseStatusEnum.JWT_EXPIRE_ERROR);
        }catch (Exception e){
            e.printStackTrace();
            return renderErrorFilter(exchange,ResponseStatusEnum.JWT_SIGNATURE_ERROR);
        }

    }

    public ServerWebExchange setNewHeaders(ServerWebExchange exchange,
                                              String headerKey,
                                              String headerValue){
        //重新构建新的request
        ServerHttpRequest newRequest = exchange.getRequest().mutate()
                                                            .header(headerKey, headerValue)
                                                            .build();

        //替换原来的request
        return exchange.mutate().request(newRequest).build();

    }

    public Mono<Void> renderErrorFilter(ServerWebExchange exchange, ResponseStatusEnum statusEnum) {

        //1.获取response、
        ServerHttpResponse response = exchange.getResponse();
        //2.构建JsonResult
        GraceJSONResult graceJSONResult = GraceJSONResult.exception(statusEnum);
        //3.修改response的code为500
        response.setStatusCode(HttpStatus.BAD_GATEWAY);
        //4.设定header类型
        if(!response.getHeaders().containsKey("Content-Type")){
            response.getHeaders().add("Content-Type", MimeTypeUtils.APPLICATION_JSON_VALUE);
        }

        //5.转换Json且向response中写入数据
        String resultJson = new Gson().toJson(graceJSONResult);
        DataBuffer dataBuffer = response.bufferFactory().wrap(resultJson.getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Mono.just(dataBuffer));


    }


    //过滤器的顺序，数字越小优先级越大
    @Override
    public int getOrder() {
        return 0;
    }
}
